home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / site-packages / impacket / structure.py < prev    next >
Text File  |  2006-05-23  |  24KB  |  694 lines

  1. # Copyright (c) 2003-2006 CORE Security Technologies
  2. #
  3. # This software is provided under under a slightly modified version
  4. # of the Apache Software License. See the accompanying LICENSE file
  5. # for more information.
  6. #
  7. # $Id: structure.py,v 1.2 2006/05/23 21:19:26 gera Exp $
  8. #
  9.  
  10. from struct import pack, unpack, calcsize
  11.  
  12. class Structure:
  13.     """ sublcasses can define commonHdr and/or structure.
  14.         each of them is an tuple of either two: (fieldName, format) or three: (fieldName, ':', class) fields.
  15.         [it can't be a dictionary, because order is important]
  16.         
  17.         where format specifies how the data in the field will be converted to/from bytes (string)
  18.         class is the class to use when unpacking ':' fields.
  19.  
  20.         each field can only contain one value (or an array of values for *)
  21.            i.e. struct.pack('Hl',1,2) is valid, but format specifier 'Hl' is not (you must use 2 dfferent fields)
  22.  
  23.         format specifiers:
  24.           specifiers from module pack can be used with the same format 
  25.           see struct.__doc__ (pack/unpack is finally called)
  26.             >       [little endian]
  27.             x       [padding byte]
  28.             c       [character]
  29.             b       [signed byte]
  30.             B       [unsigned byte]
  31.             h       [signed short]
  32.             H       [unsigned short]
  33.             l       [signed long]
  34.             L       [unsigned long]
  35.             i       [signed integer]
  36.             I       [unsigned integer]
  37.             q       [signed long long (quad)]
  38.             Q       [unsigned long ong (quad)]
  39.             s       [string (array of chars), must be preceded with length in format specifier, padded with zeros]
  40.             p       [pascal string (includes byte count), must be preceded with length in format specifier, padded with zeros]
  41.             f       [float]
  42.             d       [double]
  43.             =       [native byte ordering, size and alignment]
  44.             @       [native byte ordering, standard size and alignment]
  45.             !       [network byte ordering]
  46.             <       [little endian]
  47.             >       [big endian]
  48.  
  49.           usual printf like specifiers can be used (if started with %) 
  50.           [not recommeneded, there is no why to unpack this]
  51.  
  52.             %08x    will output an 8 bytes hex
  53.             %s      will output a string
  54.             %s\x00  will output a NUL terminated string
  55.             %d%d    will output 2 decimal digits (against the very same specification of Structure)
  56.             ...
  57.  
  58.           some additional format specifiers:
  59.             :       just copy the bytes from the field into the output string (input may be string, other structure, or anything responding to __str__()) (for unpacking, all what's left is returned)
  60.             z       same as :, but adds a NUL byte at the end (asciiz) (for unpacking the first NUL byte is used as terminator)  [asciiz string]
  61.             u       same as z, but adds two NUL bytes at the end (after padding to an even size with NULs). (same for unpacking) [unicode string]
  62.             w       DCE-RPC/NDR string (it's a macro for [  '<L=(len(field)+1)/2','"\x00\x00\x00\x00','<L=(len(field)+1)/2',':' ]
  63.             ?-field length of field named 'field', formated as specified with ? ('?' may be '!H' for example). The input value overrides the real length
  64.             ?1*?2   array of elements. Each formated as '?2', the number of elements in the array is stored as specified by '?1' (?1 is optional, or can also be a constant (number), for unpacking)
  65.             'xxxx   literal xxxx (field's value doesn't change the output. quotes must not be closed or escaped)
  66.             "xxxx   literal xxxx (field's value doesn't change the output. quotes must not be closed or escaped)
  67.             _       will not pack the field. Accepts a third argument, which is an unpack code. See _Test_UnpackCode for an example
  68.             ?=packcode  will evaluate packcode in the context of the structure, and pack the result as specified by ?. Unpacking is made plain
  69.             ?&fieldname "Address of field fieldname".
  70.                         For packing it will simply pack the id() of fieldname. Or use 0 if fieldname doesn't exists.
  71.                         For unpacking, it's used to know weather fieldname has to be unpacked or not, i.e. by adding a & field you turn another field (fieldname) in an optional field.
  72.             
  73.     """
  74.     commonHdr = ()
  75.     structure = ()
  76.     debug = 0
  77.  
  78.     def __init__(self, data = None, alignment = 0):
  79.         if not hasattr(self, 'alignment'):
  80.             self.alignment = alignment
  81.  
  82.         self.fields    = {}
  83.         if data is not None:
  84.             self.fromString(data)
  85.         else:
  86.             self.data = None
  87.  
  88.     def setAlignment(self, alignment):
  89.         self.alignment = alignment
  90.  
  91.     def setData(self, data):
  92.         self.data = data
  93.  
  94.     def packField(self, fieldName, format = None):
  95.         if self.debug:
  96.             print "packField( %s | %s )" % (fieldName, format)
  97.  
  98.         if format is None:
  99.             format = self.formatForField(fieldName)
  100.  
  101.         if self.fields.has_key(fieldName):
  102.             ans = self.pack(format, self.fields[fieldName], field = fieldName)
  103.         else:
  104.             ans = self.pack(format, None, field = fieldName)
  105.  
  106.         if self.debug:
  107.             print "\tanswer %r" % ans
  108.  
  109.         return ans
  110.  
  111.     def getData(self):
  112.         if self.data is not None:
  113.             return self.data
  114.         data = ''
  115.         for field in self.commonHdr+self.structure:
  116.             try:
  117.                 data += self.packField(field[0], field[1])
  118.             except Exception, e:
  119.                 if self.fields.has_key(field[0]):
  120.                     e.args += ("When packing field '%s | %s | %r' in %s" % (field[0], field[1], self[field[0]], self.__class__),)
  121.                 else:
  122.                     e.args += ("When packing field '%s | %s' in %s" % (field[0], field[1], self.__class__),)
  123.                 raise
  124.             if self.alignment:
  125.                 if len(data) % self.alignment:
  126.                     data += ('\x00'*self.alignment)[:-(len(data) % self.alignment)]
  127.             
  128.         #if len(data) % self.alignment: data += ('\x00'*self.alignment)[:-(len(data) % self.alignment)]
  129.         return data
  130.  
  131.     def fromString(self, data):
  132.         for field in self.commonHdr+self.structure:
  133.             if self.debug:
  134.                 print "fromString( %s | %s | %r )" % (field[0], field[1], data)
  135.             size = self.calcUnpackSize(field[1], data, field[0])
  136.             dataClassOrCode = str
  137.             if len(field) > 2:
  138.                 dataClassOrCode = field[2]
  139.             try:
  140.                 self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = dataClassOrCode, field = field[0])
  141.             except Exception,e:
  142.                 e.args += ("When unpacking field '%s | %s | %r[:%d]'" % (field[0], field[1], data, size),)
  143.                 raise
  144.  
  145.             size = self.calcPackSize(field[1], self[field[0]], field[0])
  146.             if self.alignment and size % self.alignment:
  147.                 size += self.alignment - (size % self.alignment)
  148.             data = data[size:]
  149.  
  150.         return self
  151.         
  152.     def __setitem__(self, key, value):
  153.         self.fields[key] = value
  154.         self.data = None        # force recompute
  155.  
  156.     def __getitem__(self, key):
  157.         return self.fields[key]
  158.  
  159.     def __delitem__(self, key):
  160.         del self.fields[key]
  161.         
  162.     def __str__(self):
  163.         return self.getData()
  164.  
  165.     def __len__(self):
  166.         # XXX: improve
  167.         return len(self.getData())
  168.  
  169.     def pack(self, format, data, field = None):
  170.         if self.debug:
  171.             print "  pack( %s | %r | %s)" %  (format, data, field)
  172.  
  173.         if field:
  174.             addressField = self.findAddressFieldFor(field)
  175.             if (addressField is not None) and (data is None):
  176.                 return ''
  177.  
  178.         # void specifier
  179.         if format[:1] == '_':
  180.             return ''
  181.  
  182.         # quote specifier
  183.         if format[:1] == "'" or format[:1] == '"':
  184.             return format[1:]
  185.  
  186.         # address specifier
  187.         two = format.split('&')
  188.         if len(two) == 2:
  189.             try:
  190.                 return self.pack(two[0], data)
  191.             except:
  192.                 if (self.fields.has_key(two[1])) and (self[two[1]] is not None):
  193.                     return self.pack(two[0], id(self[two[1]]))
  194.                 else:
  195.                     return self.pack(two[0], 0)
  196.  
  197.         # code specifier
  198.         two = format.split('=')
  199.         if len(two) >= 2:
  200.             try:
  201.                 return self.pack(two[0], data)
  202.             except:
  203.                 return self.pack(two[0], eval(two[1], {}, self.fields))
  204.  
  205.         # length specifier
  206.         two = format.split('-')
  207.         if len(two) == 2:
  208.             try:
  209.                 return self.pack(two[0],data)
  210.             except:
  211.                 return self.pack(two[0], self.calcPackFieldSize(two[1]))
  212.  
  213.         # array specifier
  214.         two = format.split('*')
  215.         if len(two) == 2:
  216.             answer = ''
  217.             for each in data:
  218.                 answer += self.pack(two[1], each)
  219.             if two[0]:
  220.                 if two[0].isdigit():
  221.                     if int(two[0]) != len(data):
  222.                         raise Exception, "Array field has a constant size, and it doesn't match the actual value"
  223.                 else:
  224.                     return self.pack(two[0], len(data))+answer
  225.             return answer
  226.  
  227.         # "printf" string specifier
  228.         if format[:1] == '%':
  229.             # format string like specifier
  230.             return format % data
  231.  
  232.         # asciiz specifier
  233.         if format[:1] == 'z':
  234.             return str(data)+'\0'
  235.  
  236.         # unicode specifier
  237.         if format[:1] == 'u':
  238.             return str(data)+'\0\0' + (len(data) & 1 and '\0' or '')
  239.  
  240.         # DCE-RPC/NDR string specifier
  241.         if format[:1] == 'w':
  242.             if len(data) == 0:
  243.                 data = '\0\0'
  244.             elif len(data) % 2:
  245.                 data += '\0'
  246.             l = pack('<L', len(data)/2)
  247.             return '%s\0\0\0\0%s%s' % (l,l,data)
  248.                     
  249.         if data is None:
  250.             raise Exception, "Trying to pack None"
  251.         
  252.         # literal specifier
  253.         if format[:1] == ':':
  254.             return str(data)
  255.  
  256.         # struct like specifier
  257.         return pack(format, data)
  258.  
  259.     def unpack(self, format, data, dataClassOrCode = str, field = None):
  260.         if self.debug:
  261.             print "  unpack( %s | %r )" %  (format, data)
  262.  
  263.         if field:
  264.             addressField = self.findAddressFieldFor(field)
  265.             if addressField is not None:
  266.                 if not self[addressField]:
  267.                     return
  268.  
  269.         # void specifier
  270.         if format[:1] == '_':
  271.             if dataClassOrCode != str:
  272.                 return eval(dataClassOrCode, {}, self.fields)
  273.  
  274.         # quote specifier
  275.         if format[:1] == "'" or format[:1] == '"':
  276.             answer = format[1:]
  277.             if answer != data:
  278.                 raise Exception, "Unpacked data doesn't match constant value '%r' should be '%r'" % (data, answer)
  279.             return answer
  280.  
  281.         # address specifier
  282.         two = format.split('&')
  283.         if len(two) == 2:
  284.             return self.unpack(two[0],data)
  285.  
  286.         # code specifier
  287.         two = format.split('=')
  288.         if len(two) >= 2:
  289.             return self.unpack(two[0],data)
  290.  
  291.         # length specifier
  292.         two = format.split('-')
  293.         if len(two) == 2:
  294.             return self.unpack(two[0],data)
  295.  
  296.         # array specifier
  297.         two = format.split('*')
  298.         if len(two) == 2:
  299.             answer = []
  300.             sofar = 0
  301.             if two[0].isdigit():
  302.                 number = int(two[0])
  303.             elif two[0]:
  304.                 sofar += self.calcUnpackSize(two[0], data)
  305.                 number = self.unpack(two[0], data[:sofar])
  306.             else:
  307.                 number = -1
  308.  
  309.             while number and sofar < len(data):
  310.                 nsofar = sofar + self.calcUnpackSize(two[1],data[sofar:])
  311.                 answer.append(self.unpack(two[1], data[sofar:nsofar], dataClassOrCode))
  312.                 number -= 1
  313.                 sofar = nsofar
  314.             return answer
  315.  
  316.         # "printf" string specifier
  317.         if format[:1] == '%':
  318.             # format string like specifier
  319.             return format % data
  320.  
  321.         # asciiz specifier
  322.         if format == 'z':
  323.             if data[-1] != '\x00':
  324.                 raise Exception, ("%s 'z' field is not NUL terminated: %r" % (field, data))
  325.             return data[:-1] # remove trailing NUL
  326.  
  327.         # unicode specifier
  328.         if format == 'u':
  329.             if data[-2:] != '\x00\x00':
  330.                 raise Exception, ("%s 'u' field is not NUL-NUL terminated: %r" % (field, data))
  331.             return data[:-2] # remove trailing NUL
  332.  
  333.         # DCE-RPC/NDR string specifier
  334.         if format == 'w':
  335.             l = unpack('<L', data[:4])[0]
  336.             return data[12:12+l*2]
  337.  
  338.         # literal specifier
  339.         if format == ':':
  340.             return dataClassOrCode(data)
  341.  
  342.         # struct like specifier
  343.         return unpack(format, data)[0]
  344.  
  345.     def calcPackSize(self, format, data, field = None):
  346. #        # print "  calcPackSize  %s:%r" %  (format, data)
  347.         if field:
  348.             addressField = self.findAddressFieldFor(field)
  349.             if addressField is not None:
  350.                 if not self[addressField]:
  351.                     return 0
  352.  
  353.         # void specifier
  354.         if format[:1] == '_':
  355.             return 0
  356.  
  357.         # quote specifier
  358.         if format[:1] == "'" or format[:1] == '"':
  359.             return len(format)-1
  360.  
  361.         # address specifier
  362.         two = format.split('&')
  363.         if len(two) == 2:
  364.             return self.calcPackSize(two[0], data)
  365.  
  366.         # code specifier
  367.         two = format.split('=')
  368.         if len(two) >= 2:
  369.             return self.calcPackSize(two[0], data)
  370.  
  371.         # length specifier
  372.         two = format.split('-')
  373.         if len(two) == 2:
  374.             return self.calcPackSize(two[0], data)
  375.  
  376.         # array specifier
  377.         two = format.split('*')
  378.         if len(two) == 2:
  379.             answer = 0
  380.             if two[0].isdigit():
  381.                     if int(two[0]) != len(data):
  382.                         raise Exception, "Array field has a constant size, and it doesn't match the actual value"
  383.             elif two[0]:
  384.                 answer += self.calcPackSize(two[0], len(data))
  385.  
  386.             for each in data:
  387.                 answer += self.calcPackSize(two[1], each)
  388.             return answer
  389.  
  390.         # "printf" string specifier
  391.         if format[:1] == '%':
  392.             # format string like specifier
  393.             return len(format % data)
  394.  
  395.         # asciiz specifier
  396.         if format[:1] == 'z':
  397.             return len(data)+1
  398.  
  399.         # asciiz specifier
  400.         if format[:1] == 'u':
  401.             l = len(data)
  402.             return l + (l & 1 and 3 or 2)
  403.  
  404.         # DCE-RPC/NDR string specifier
  405.         if format[:1] == 'w':
  406.             l = len(data)
  407.             return 12+l+l % 2
  408.  
  409.         # literal specifier
  410.         if format[:1] == ':':
  411.             return len(data)
  412.  
  413.         # struct like specifier
  414.         return calcsize(format)
  415.  
  416.     def calcUnpackSize(self, format, data, field = None):
  417.         if self.debug:
  418.             print "  calcUnpackSize( %s | %s | %r)" %  (field, format, data)
  419.  
  420.         addressField = self.findAddressFieldFor(field)
  421.         if addressField is not None:
  422.             if not self[addressField]:
  423.                 return 0
  424.  
  425.         try:
  426.             lengthField = self.findLengthFieldFor(field)
  427.             return self[lengthField]
  428.         except:
  429.             pass
  430.  
  431.         # XXX: Try to match to actual values, raise if no match
  432.         
  433.         # void specifier
  434.         if format[:1] == '_':
  435.             return 0
  436.  
  437.         # quote specifier
  438.         if format[:1] == "'" or format[:1] == '"':
  439.             return len(format)-1
  440.  
  441.         # address specifier
  442.         two = format.split('&')
  443.         if len(two) == 2:
  444.             return self.calcUnpackSize(two[0], data)
  445.  
  446.         # code specifier
  447.         two = format.split('=')
  448.         if len(two) >= 2:
  449.             return self.calcUnpackSize(two[0], data)
  450.  
  451.         # length specifier
  452.         two = format.split('-')
  453.         if len(two) == 2:
  454.             return self.calcUnpackSize(two[0], data)
  455.  
  456.         # array specifier
  457.         two = format.split('*')
  458.         if len(two) == 2:
  459.             answer = 0
  460.             if two[0]:
  461.                 if two[0].isdigit():
  462.                     number = int(two[0])
  463.                 else:
  464.                     answer += self.calcUnpackSize(two[0], data)
  465.                     number = self.unpack(two[0], data[:answer])
  466.  
  467.                 while number:
  468.                     number -= 1
  469.                     answer += self.calcUnpackSize(two[1], data[answer:])
  470.             else:
  471.                 while answer < len(data):
  472.                     answer += self.calcUnpackSize(two[1], data[answer:])
  473.             return answer
  474.  
  475.         # "printf" string specifier
  476.         if format[:1] == '%':
  477.             raise Exception, "Can't guess the size of a printf like specifier for unpacking"
  478.  
  479.         # asciiz specifier
  480.         if format[:1] == 'z':
  481.             return data.index('\x00')+1
  482.  
  483.         # asciiz specifier
  484.         if format[:1] == 'u':
  485.             l = data.index('\x00\x00')
  486.             return l + (l & 1 and 3 or 2)
  487.  
  488.         # DCE-RPC/NDR string specifier
  489.         if format[:1] == 'w':
  490.             l = unpack('<L', data[:4])[0]
  491.             return 12+l*2
  492.  
  493.         # literal specifier
  494.         if format[:1] == ':':
  495.             return len(data)
  496.  
  497.         # struct like specifier
  498.         return calcsize(format)
  499.  
  500.     def calcPackFieldSize(self, fieldName, format = None):
  501.         if format is None:
  502.             format = self.formatForField(fieldName)
  503.  
  504.         return self.calcPackSize(format, self[fieldName])
  505.  
  506.     def formatForField(self, fieldName):
  507.         for field in self.commonHdr+self.structure:
  508.             if field[0] == fieldName:
  509.                 return field[1]
  510.         raise Exception, ("Field %s not found" % fieldName)
  511.  
  512.     def findAddressFieldFor(self, fieldName):
  513.         descriptor = '&%s' % fieldName
  514.         l = len(descriptor)
  515.         for field in self.commonHdr+self.structure:
  516.             if field[1][-l:] == descriptor:
  517.                 return field[0]
  518.         return None
  519.         
  520.     def findLengthFieldFor(self, fieldName):
  521.         descriptor = '-%s' % fieldName
  522.         l = len(descriptor)
  523.         for field in self.commonHdr+self.structure:
  524.             if field[1][-l:] == descriptor:
  525.                 return field[0]
  526.         return None
  527.         
  528.     def zeroValue(self, format):
  529.         two = format.split('*')
  530.         if len(two) == 2:
  531.             if two[0].isdigit():
  532.                 return (self.zeroValue(two[1]),)*int(two[0])
  533.                         
  534.         if not format.find('*') == -1: return ()
  535.         if 's' in format: return ''
  536.         if format in ['z',':','u']: return ''
  537.         if format == 'w': return '\x00\x00'
  538.  
  539.         return 0
  540.  
  541.     def clear(self):
  542.         for field in self.commonHdr + self.structure:
  543.             self[field[0]] = self.zeroValue(field[1])
  544.  
  545.     def dump(self, msg, indent = 0):
  546.         import types
  547.         ind = ' '*indent
  548.         print "\n%s" % (msg)
  549.         for i in self.fields.keys():
  550.             if isinstance(self[i], Structure):
  551.                 self[i].dump('%s:{' % i, indent = indent + 4)
  552.                 print "}"
  553.             else:
  554.                 print "%s%s: {%r}" % (ind,i,self[i])
  555.  
  556. class _StructureTest:
  557.     alignment = 0
  558.     def create(self,data = None):
  559.         if data is not None:
  560.             return self.theClass(data, alignment = self.alignment)
  561.         else:
  562.             return self.theClass(alignment = self.alignment)
  563.  
  564.     def run(self):
  565.         print
  566.         print "-"*70
  567.         testName = self.__class__.__name__
  568.         print "starting test: %s....." % testName
  569.         a = self.create()
  570.         self.populate(a)
  571.         a.dump("packing.....")
  572.         a_str = str(a)
  573.         print "packed: %r" % a_str
  574.         print "unpacking....."
  575.         b = self.create(a_str)
  576.         b.dump("unpacked.....")
  577.         print "repacking....."
  578.         b_str = str(b)
  579.         if b_str != a_str:
  580.             print "ERROR: original packed and repacked don't match"
  581.             print "packed: %r" % b_str
  582.  
  583. class _Test_simple(_StructureTest):
  584.     class theClass(Structure):
  585.         commonHdr = ()
  586.         structure = (
  587.                 ('int1', '!L'),
  588.                 ('len1','!L-z1'),
  589.                 ('arr1','B*<L'),
  590.                 ('z1', 'z'),
  591.                 ('u1','u'),
  592.                 ('', '"COCA'),
  593.                 ('len2','!H-:1'),
  594.                 ('', '"COCA'),
  595.                 (':1', ':'),
  596.                 ('int3','>L'),
  597.                 ('code1','>L=len(arr1)*2+0x1000'),
  598.                 )
  599.  
  600.     def populate(self, a):
  601.         a['default'] = 'hola'
  602.         a['int1'] = 0x3131
  603.         a['int3'] = 0x45444342
  604.         a['z1']   = 'hola'
  605.         a['u1']   = 'hola'.encode('utf_16_le')
  606.         a[':1']   = ':1234:'
  607.         a['arr1'] = (0x12341234,0x88990077,0x41414141)
  608.         # a['len1'] = 0x42424242
  609.  
  610. class _Test_fixedLength(_Test_simple):
  611.     def populate(self, a):
  612.         _Test_simple.populate(self, a)
  613.         a['len1'] = 0x42424242
  614.  
  615. class _Test_simple_aligned4(_Test_simple):
  616.     alignment = 4
  617.  
  618. class _Test_nested(_StructureTest):
  619.     class theClass(Structure):
  620.         class _Inner(Structure):
  621.             structure = (('data', 'z'),)
  622.  
  623.         structure = (
  624.             ('nest1', ':', _Inner),
  625.             ('nest2', ':', _Inner),
  626.             ('int', '<L'),
  627.         )
  628.  
  629.     def populate(self, a):
  630.         a['nest1'] = _Test_nested.theClass._Inner()
  631.         a['nest2'] = _Test_nested.theClass._Inner()
  632.         a['nest1']['data'] = 'hola manola'
  633.         a['nest2']['data'] = 'chau loco'
  634.         a['int'] = 0x12345678
  635.     
  636. class _Test_Optional(_StructureTest):
  637.     class theClass(Structure):
  638.         structure = (
  639.                 ('pName','<L&Name'),
  640.                 ('pList','<L&List'),
  641.                 ('Name','w'),
  642.                 ('List','<H*<L'),
  643.             )
  644.             
  645.     def populate(self, a):
  646.         a['Name'] = 'Optional test'
  647.         a['List'] = (1,2,3,4)
  648.         
  649. class _Test_Optional_sparse(_Test_Optional):
  650.     def populate(self, a):
  651.         _Test_Optional.populate(self, a)
  652.         del a['Name']
  653.  
  654. class _Test_AsciiZArray(_StructureTest):
  655.     class theClass(Structure):
  656.         structure = (
  657.             ('head','<L'),
  658.             ('array','B*z'),
  659.             ('tail','<L'),
  660.         )
  661.  
  662.     def populate(self, a):
  663.         a['head'] = 0x1234
  664.         a['tail'] = 0xabcd
  665.         a['array'] = ('hola','manola','te traje')
  666.         
  667. class _Test_UnpackCode(_StructureTest):
  668.     class theClass(Structure):
  669.         structure = (
  670.             ('leni','<L=len(uno)*2'),
  671.             ('cuchi','_-uno','leni/2'),
  672.             ('uno',':'),
  673.             ('dos',':'),
  674.         )
  675.  
  676.     def populate(self, a):
  677.         a['uno'] = 'soy un loco!'
  678.         a['dos'] = 'que haces fiera'
  679.  
  680. if __name__ == '__main__':
  681.     _Test_simple().run()
  682.  
  683.     try:
  684.         _Test_fixedLength().run()
  685.     except:
  686.         print "cannot repack because length is bogus"
  687.  
  688.     _Test_simple_aligned4().run()
  689.     _Test_nested().run()
  690.     _Test_Optional().run()
  691.     _Test_Optional_sparse().run()
  692.     _Test_AsciiZArray().run()
  693.     _Test_UnpackCode().run()
  694.